package com.vehiclemanagement.aspect;

import com.alibaba.fastjson2.JSON;
import com.vehiclemanagement.annotation.OperationLogAnnotation;
import com.vehiclemanagement.entity.OperationLog;
import com.vehiclemanagement.service.OperationLogService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Map;
import java.util.Optional;

/**
 * 操作日志切面
 */
@Aspect
@Component
@Slf4j
public class OperationLogAspect {

    @Autowired
    private OperationLogService operationLogService;

    /**
     * 切入点
     */
    @Pointcut("@annotation(com.vehiclemanagement.annotation.OperationLogAnnotation)")
    public void operationLogPointCut() {
    }

    /**
     * 环绕通知
     */
    @Around("operationLogPointCut()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        // 开始时间
        long startTime = System.currentTimeMillis();
        
        // 执行方法
        Object result = joinPoint.proceed();
        
        // 执行时间
        long executeTime = System.currentTimeMillis() - startTime;
        
        // 记录成功的日志
        saveLog(joinPoint, result, executeTime, null);
        
        return result;
    }

    /**
     * 异常通知
     */
    @AfterThrowing(value = "operationLogPointCut()", throwing = "e")
    public void doAfterThrowing(JoinPoint joinPoint, Exception e) {
        // 记录异常日志
        saveLog(joinPoint, null, 0L, e);
    }

    /**
     * 保存操作日志
     */
    private void saveLog(JoinPoint joinPoint, Object result, long executeTime, Exception e) {
        try {
            // 获取请求信息
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = Optional.ofNullable(attributes).map(ServletRequestAttributes::getRequest).orElse(null);
            
            // 获取注解信息
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();
            OperationLogAnnotation logAnnotation = method.getAnnotation(OperationLogAnnotation.class);
            
            // 创建日志对象
            OperationLog operationLog = new OperationLog();
            
            // 设置用户信息
            Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
            if (authentication != null && authentication.isAuthenticated() && !"anonymousUser".equals(authentication.getPrincipal())) {
                // 如果是UserDetails类型
                if (authentication.getPrincipal() instanceof org.springframework.security.core.userdetails.User) {
                    org.springframework.security.core.userdetails.User securityUser = 
                            (org.springframework.security.core.userdetails.User) authentication.getPrincipal();
                    operationLog.setUsername(securityUser.getUsername());
                    
                    // 此处可能需要通过用户名查询用户ID
                    // 假设authentication.getDetails()中包含用户ID信息
                    if (authentication.getDetails() instanceof Map) {
                        Map<String, Object> details = (Map<String, Object>) authentication.getDetails();
                        if (details.containsKey("userId")) {
                            operationLog.setUserId(Long.valueOf(details.get("userId").toString()));
                        }
                    }
                }
            }
            
            // 设置请求信息
            if (request != null) {
                operationLog.setRequestUrl(request.getRequestURI());
                operationLog.setRequestMethod(request.getMethod());
                operationLog.setOperationIp(getIpAddress(request));
                
                // 获取请求参数
                String params = Arrays.toString(joinPoint.getArgs());
                if (params.length() > 2000) {
                    params = params.substring(0, 2000) + "...";
                }
                operationLog.setRequestParams(params);
            }
            
            // 设置方法信息
            operationLog.setMethod(joinPoint.getTarget().getClass().getName() + "." + method.getName());
            
            // 设置注解信息
            operationLog.setModule(logAnnotation.module());
            operationLog.setOperationType(logAnnotation.operationType());
            operationLog.setDescription(logAnnotation.description());
            
            // 设置响应信息
            if (result != null) {
                String responseStr = JSON.toJSONString(result);
                if (responseStr.length() > 2000) {
                    responseStr = responseStr.substring(0, 2000) + "...";
                }
                operationLog.setResponseResult(responseStr);
            }
            
            // 设置异常信息
            if (e != null) {
                operationLog.setStatus(0); // 失败
                operationLog.setErrorMessage(e.getMessage());
                if (operationLog.getErrorMessage() != null && operationLog.getErrorMessage().length() > 2000) {
                    operationLog.setErrorMessage(operationLog.getErrorMessage().substring(0, 2000) + "...");
                }
            } else {
                operationLog.setStatus(1); // 成功
            }
            
            // 设置操作时间
            operationLog.setOperationTime(executeTime);
            operationLog.setCreateTime(LocalDateTime.now());
            
            // 保存日志
            operationLogService.saveLog(operationLog);
        } catch (Exception ex) {
            log.error("记录操作日志失败", ex);
        }
    }

    /**
     * 获取IP地址
     */
    private String getIpAddress(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        if (ip.contains(",")) {
            ip = ip.split(",")[0];
        }
        return ip;
    }
} 